package com.biz.primus.ms.price.service;

import com.biz.primus.base.vo.PriceVo;
import com.biz.primus.base.vo.price.PriceItemVo;
import com.biz.primus.common.utils.CopyUtils;
import com.biz.primus.common.utils.JsonUtils;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.price.vo.*;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.price.dao.po.Price;
import com.biz.primus.ms.price.dao.po.SpecPrice;
import com.biz.primus.ms.price.dao.redis.PriceRedisDao;
import com.biz.primus.ms.price.dao.repository.PriceRepository;
import com.biz.primus.ms.price.dao.repository.SpecPriceRepository;
import com.biz.primus.ms.price.dao.ro.PriceRo;
import com.biz.primus.ms.price.dao.specification.PriceSpecification;
import com.biz.primus.ms.price.feign.DepotFeignClient;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

/**
 * @author jiangnan
 * @Description: 商品查询价格接口
 * @create 2017-10-10-上午11:51
 */
@Service
@Slf4j
public class PriceService extends AbstractPriceService {

    @Autowired
    private PriceRedisDao priceRedisDao;

    @Autowired
    private DepotFeignClient depotService;

    @Autowired
    private PriceRepository priceRepository;

    @Autowired
    private SpecPriceRepository specPriceRepository;

    public void syncSpecPrices(List<SyncSpecPriceVo> reqVos) {
        log.info("syncSpecPrices reqVos {}", JsonUtils.obj2Json(reqVos));
        int errorCount = 0;
        for (SyncSpecPriceVo index : reqVos) {
            try{
                syncSpecPrice(index);
            }catch (Exception e){
                errorCount++;
                log.warn("syncSpec warn {}",index);
                e.printStackTrace();
            }
        }
        log.info("syncSpecPrices total {} ,error {}",reqVos.size(),errorCount);
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void syncSpecPrice(SyncSpecPriceVo syncSpecPriceVo){
        SpecPrice specPrice = specPriceRepository.findByDepotCodeAndProductCodeAndPackageId(syncSpecPriceVo.getDepotCode(),
                syncSpecPriceVo.getProductCode(),syncSpecPriceVo.getPackageId());
        if (specPrice == null){
            specPrice = new SpecPrice();
            specPrice.setId(idService.getNextId());
        }
        CopyUtils.copyProperties(syncSpecPriceVo,specPrice);
        specPriceRepository.save(specPrice);
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncPrices(List<SyncPriceVo> reqVos) {
        log.info("syncPrices reqVos {}", JsonUtils.obj2Json(reqVos));
        List<PriceRo> priceRos = Lists.newArrayList();
        Long errorCount = 0L;
        List<Price> prices = Lists.newArrayList();
        for (SyncPriceVo index : reqVos) {
            if (index.valid()) {
                Price price = priceRepository.findByProductCodeAndDepotCode(index.getProductCode(), index.getDepotCode());
                if (price == null) {
                    price = new Price();
                }
                CopyUtils.copyProperties(index, price);
                PriceRo priceRo = new PriceRo();
                priceRo.from(index);
                priceRos.add(priceRo);
                prices.add(price);
            } else {
                log.warn("价格数据异常 {}", index);
                errorCount++;
                continue;
            }
        }
        priceRepository.save(prices);
        this.delayer.executeAfterTransactionCommit(()->priceRedisDao.save(priceRos));
        log.info("syncPrices complete total {} error {}", reqVos.size(), errorCount);
    }

    public BatchPriceVo prices(PriceReqVo priceReqVo) {
        BatchPriceVo respVo = new BatchPriceVo();
        List<PriceRo> depotPrices = priceRedisDao.getTypeBPrices(priceReqVo.getProductCodes(), priceReqVo.getDepotCode());
        List<PriceVo> depotPriceVos = Optional.ofNullable(depotPrices).orElse(Lists.newArrayList()).stream().map(this::priceRo2PriceVo).collect(toList());
        respVo.setDepotPrices(depotPriceVos);
        List<PriceRo> virtualDepotPrices = priceRedisDao.getTypeBPrices(priceReqVo.getProductCodes(), priceReqVo.getVirtualDepotCode());
        List<PriceVo> virtualDepotPriceVos = Optional.ofNullable(virtualDepotPrices).orElse(Lists.newArrayList()).stream().map(this::priceRo2PriceVo).collect(toList());
        respVo.setVirtualPrices(virtualDepotPriceVos);
        return respVo;
    }


    public SpringPageVO<PriceItemVo> findAllPrice(PriceQueryVo reqVo) {
        Page<Price> all = priceRepository.findAll(new PriceSpecification(reqVo), reqVo.toPageRequest());
        return SpringPageToSpringPageVO.of(all, (Price price) -> CopyUtils.copyProperties(price, new PriceItemVo()));
    }

    public List<PriceVo> findByIdsWithNull(List<String> ids) {
        List<PriceRo> ros = priceRedisDao.findByIdsWithNull(ids);
        return this.priceRos2PriceVos(ros);
    }

}
